package com.rub.android.utils

import android.util.Log
import com.blankj.utilcode.util.StringUtils
import com.google.gson.Gson
import okhttp3.*


import java.io.*
import java.lang.Exception
import java.lang.StringBuilder
import java.lang.reflect.ParameterizedType
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.HashMap
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import javax.net.ssl.*


/**
 * @Description
 * ==========================================================================================
 * 参考博客：http://www.cnblogs.com/whoislcj/p/5526431.html
 * http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html
 * ==========================================================================================
 * 秒的换算：ms(毫秒)millisecond ,μs(微秒)microsecond ,ns(纳秒)nanosecond ,ps(皮秒)picosecond
 * 秒的换算  http://blog.chinaunix.net/uid-28458801-id-4144886.html
 * Semaphored的使用： http://www.cnblogs.com/whgw/archive/2011/09/29/2195555.html
 * ==========================================================================================
 * ==========================================================================================
 * @ClassName   OkHttpClientUtil
 * @Date        2017年7月10日 下午5:39:49
 * @Author      liangjilong
 * @Copyright (c) All Rights Reserved, 2017.
 */
object OkHttpClientUtil {

    //private static String JSON = "application/json; charset=utf-8";
    private const val MEDIA_TYPE_JSON = "application/x-www-form-urlencoded; charset=utf-8"

    /**使用volatile双重校验锁 */
    @Volatile
    private var semaphore: Semaphore? = null

    @Volatile
    private var okHttpClient: OkHttpClient? = null//只能0个线程同时访问

    /**建立单例模式 */
    val semaphoreInstance: Semaphore?
        get() {
            //只能0个线程同时访问
            synchronized(OkHttpClientUtil::class.java) {
                if (semaphore == null) {
                    semaphore = Semaphore(0)
                }
            }
            return semaphore
        }

    /**建立单例模式 */
    private val instance: OkHttpClient?
        get() {
            synchronized(OkHttpClientUtil::class.java) {
                if (okHttpClient == null) {
                    //这里是以毫秒为单位，1000 毫秒 = 1秒
                    okHttpClient = OkHttpClient().newBuilder()
                        .connectTimeout(5000, TimeUnit.SECONDS) // 设置超时时间
                        .readTimeout(5000, TimeUnit.SECONDS) // 设置读取超时时间
                        .writeTimeout(5000, TimeUnit.SECONDS) // 设置写入超时时间
                        .build()
                }
            }
            return okHttpClient
        }

    @Throws(Exception::class)
    @JvmStatic
    fun main(args: Array<String>) {
        /**组装参数 */
        val reqMap: MutableMap<String, Any> = HashMap()
        reqMap["id"] = "1"

        //============================测试7==============================
        val url = "https://www.12306.cn/mormhweb/"
        val retMsg = createHttpsPost(url, null, MEDIA_TYPE_JSON)
        println(retMsg)
    }

    /**
     * @Description 求在子线程发起网络请求
     * @Author      liangjilong
     * @Date        2017年7月10日 下午3:53:49
     * @param url 请求url地址
     * @param params  请求body参数
     * @param okHttpClientCall 回调接口
     * @throws IOException 参数
     * @return void 返回类型
     */
    fun createAsycHttpGet(
        url: String,
        params: Map<String, Any>,
        okHttpClientCall: IOkHttpClientCallBack
    ) {
        // 创建请求对象
        val call = createCall(url, params)
        //发起异步的请求
        call.enqueue(object : Callback {
            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                if (response != null && response.isSuccessful) {
                    val string = response.body()!!.string()
                    okHttpClientCall.onSuccessful(string)
                }
            }

            override fun onFailure(call: Call, e: IOException) {
                val errorLog = currentClassName + "#createHttpGet,请求异常，异常信息为:" + e.message
            }
        })
    }

    /**
     * @Description 求在子线程发起网络请求
     * @Date        2017年7月10日 下午3:53:49
     * @param url 请求url地址
     * @param params  请求body参数
     * @param okHttpClientCall 回调接口
     * @throws IOException 参数
     * @return void 返回类型
     */
    fun createAsycHttpGet(url: String, params: Map<String, Any>): String {
        val buffer = StringBuilder("")
        try {
            // 创建请求对象
            val call = createCall(url, params)

            //发起异步的请求
            call.enqueue(object : Callback {
                @Throws(IOException::class)
                override fun onResponse(call: Call, response: Response) {
                    if (response != null && response.isSuccessful) {
                        val string = response.body()!!.string()
                        buffer.append(string)
                        semaphoreInstance!!.release()
                    }
                }

                override fun onFailure(call: Call, e: IOException) {
                    val errorLog = currentClassName + "#createHttpGet,请求异常，异常信息为:" + e.message
                }
            })
            semaphoreInstance!!.acquire() //获取许可
            return buffer.toString()
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        return buffer.toString()
    }

    /**
     * @Description 求在子线程发起网络请求
     * @Author      liangjilong
     * @Date        2017年7月10日 下午3:53:49
     * @param url 请求url地址
     * @param params  请求body参数
     * @param okHttpClientCall 回调接口
     * @throws IOException 参数
     * @return void 返回类型
     */
    fun createHttpGet(url: String, params: Map<String, Any>): String {
        try {
            // 创建请求对象
            val call = createCall(url, params)
            val response = call.execute()
            if (response != null && response.isSuccessful && ObjectUtil.isNotEmpty(response.body())) {
                return convertToString(response.body()!!.byteStream())
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return ""
    }

    /**
     * @Description convertStreamToString
     * @Author        liangjl
     * @Date        2018年2月9日 下午3:02:00
     * @param is
     * @return 参数
     * @return String 返回类型
     * @throws
     */
    fun convertToString(`is`: InputStream): String {
        val reader = BufferedReader(InputStreamReader(`is`))
        val buffer = StringBuilder()
        var line: String? = null
        try {
            while (reader.readLine().also { line = it } != null) {
                buffer.append(line + "\r")
            }
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            try {
                `is`.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        return buffer.toString()
    }

    /**
     * @Description convertStr
     * @Author        liangjl
     * @Date        2018年2月9日 下午3:01:49
     * @param is
     * @return
     * @throws IOException 参数
     * @return String 返回类型
     * @throws
     */
    @Throws(IOException::class)
    fun convertStr(`is`: InputStream): String {
        val baos: OutputStream = ByteArrayOutputStream()
        var i = -1
        while (`is`.read().also { i = it } != -1) {
            baos.write(i)
        }
        return baos.toString()
    }

    /**
     * @Description 创建异步表单Body参数的post请求处理
     * @Author      liangjilong
     * @Date        2017年7月11日 上午9:46:04
     * @param url   请求链接
     * @param params 请求表单body参数
     * @param okHttpClientCall 参数  回调接口
     * @return void 返回类型
     */
    fun createPostByAsynWithForm(
        url: String,
        params: Map<String?, Any>,
        okHttpClientCall: IOkHttpClientCallBack
    ) {
        val builder = FormBody.Builder()
        for (key in params.keys) {
            builder.add(key, params[key].toString())
        }
        val formBody: RequestBody = builder.build()
        val request = Request.Builder().url(url).post(formBody).build()
        // 创建请求对象
        val call = instance!!.newCall(request)
        //发起异步的请求
        call.enqueue(object : Callback {
            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                if (response != null && response.isSuccessful) {
                    val string = response.body()!!.string()
                    okHttpClientCall.onSuccessful(string)
                }
            }

            override fun onFailure(call: Call, e: IOException) {
                val errorLog =
                    currentClassName + "#createPostByAsynWithForm,请求异常，异常信息为:" + e.message
            }
        })
    }

    /**
     * @Description 创建异步表单Body参数的post请求处理
     * @Author      liangjilong
     * @Date        2017年7月11日 上午9:46:04
     * @param url   请求链接
     * @param params 请求表单body参数
     * @param okHttpClientCall 参数  回调接口
     * @return
     * @return void 返回类型
     */
    fun createPostByAsynWithForm(url: String, params: Map<String?, Any>): String {
        val buffer = StringBuilder("")
        try {
            val builder = FormBody.Builder()
            for (key in params.keys) {
                builder.add(key, params[key].toString())
            }
            val formBody: RequestBody = builder.build()
            Log.i(
                "createPostByAsynWithForm: ",
                "@see" + currentClassName + "请求url" + url + ",请求参数:" + formBody
            )
            val request = Request.Builder().url(url).post(formBody).build()
            // 创建请求对象
            val call = instance!!.newCall(request)
            //发起异步的请求
            call.enqueue(object : Callback {
                @Throws(IOException::class)
                override fun onResponse(call: Call, response: Response) {
                    if (response != null && response.isSuccessful) {
                        val string = response.body()!!.string()
                        buffer.append(string)
                        semaphoreInstance!!.release()
                    }
                }

                override fun onFailure(call: Call, e: IOException) {
                    val errorLog =
                        currentClassName + "#createPostByAsynWithForm,请求异常，异常信息为:" + e.message
                    Log.i("createPostByAsynWithForm: ", "@see $errorLog")
                }
            })
            semaphoreInstance!!.acquire()
            return buffer.toString()
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        return buffer.toString()
    }

    /**
     * okHttp createCall
     * @param url  接口地址
     * @param params   请求参数
     */
    private fun createCall(url: String, params: Map<String, Any>): Call {
        //补全请求地址,【%s?%s或者%s/%s的使用】第一个%s代表第一个参数，第二个?代表是请求地址的?后面%s代表是组装戳参数,如：
        //http://localhost:8080/api/test.do?userId=1212&deviceInfo=PC
        val requestUrl = String.format("%s?%s", url, concatParams(params).toString())
        //创建一个请求
        val request = Request.Builder().url(requestUrl).build()
        return instance!!.newCall(request)
    }

    /**
     * @Description createHttpPost
     * @Author      liangjilong
     * @Date        2017年7月11日 下午12:20:04
     * @param url
     * @param reqMap
     * @param contentType
     * @return 参数
     * @return String 返回类型
     */
    fun createHttpPost(url: String?, reqMap: Map<String, Any>?, contentType: String): String {
        try {
            val body = createRequestBody(contentType, reqMap)
            //logger.info("@see"+getCurrentClassName()+"#createHttpPost,请求url"+url+",请求参数:"+body.toString());
            val request = Request.Builder().url(url).post(body).build()
            // 创建请求对象
            val call = instance!!.newCall(request)
            val response = call.execute()
            if (response != null && response.isSuccessful) {
                return convertStr(response.body()!!.byteStream())
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return ""
    }

    /**
     * @Description 在子线程发起 post 请求
     * @Author      liangjilong
     * @Date        2017年7月10日 下午3:58:39
     * @param url 参数
     * @return void 返回类型
     */
    fun createAsycHttpPost(url: String?, reqMap: Map<String, Any>?, contentType: String): String {
        val buffer = StringBuilder("")
        try {
            val body = createRequestBody(contentType, reqMap)

            //logger.info("@see"+getCurrentClassName()+"#createHttpPost,请求url"+url+",请求参数:"+body.toString());
            val request = Request.Builder().url(url).post(body).build()
            // 创建请求对象
            val call = instance!!.newCall(request)

            // 发起请求
            call.enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    val errorLog = currentClassName + "#createHttpPost,请求异常，异常信息为:" + e.message
                    Log.i("createAsycHttpPost: ", "@see $errorLog")
                }

                @Throws(IOException::class)
                override fun onResponse(call: Call, response: Response) {
                    if (response != null && response.isSuccessful) {
                        if (!StringUtils.isEmpty(response.body().toString())) {
                            val string = response.body()!!.string()
                            buffer.append(string)
                            semaphoreInstance!!.release() //释放
                        }
                    }
                }
            })
            semaphoreInstance!!.acquire() //接受
            return buffer.toString()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return buffer.toString()
    }

    /**
     * @Description 在子线程发起 post 请求
     * @Author      liangjilong
     * @Date        2017年7月10日 下午3:58:39
     * @param url 参数
     * @return void 返回类型
     */
    fun createAsycHttpPost(
        url: String?,
        reqMap: Map<String, Any>?,
        contentType: String,
        okHttpClientCall: IOkHttpClientCallBack
    ) {
        val body = createRequestBody(contentType, reqMap)

        //logger.info("@see"+getCurrentClassName()+"#createHttpPost,请求url"+url+",请求参数:"+body.toString());
        val request = Request.Builder().url(url).post(body).build()
        // 创建请求对象
        val call = instance!!.newCall(request)

        // 发起请求
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                val errorLog = currentClassName + "#createHttpPost,请求异常，异常信息为:" + e.message
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                if (response != null && response.isSuccessful) {
                    if (!StringUtils.isEmpty(response.body()?.string())) {
                        val retBody = response.body()!!.string()
                        okHttpClientCall.onSuccessful(retBody)
                    }
                }
            }
        })
    }

    /**
     *
     * @Description 组装参数
     * @Author      liangjilong
     * @Date        2017年7月10日 下午5:48:13
     * @param contentType  请求头header属性
     * @param params       请求参数
     * @return 参数
     * @return RequestBody 返回类型
     */
    private fun createRequestBody(contentType: String, params: Map<String, Any>?): RequestBody {
        val type = MediaType.parse(contentType)
        val paramStrs = concatParams(params).toString()
        return RequestBody.create(type, paramStrs)
    }

    /**
     * @Description 拼接参数
     * @Author      liangjilong
     * @Date        2017年7月11日 上午9:34:00
     * @param params
     * @return 参数
     * @return StringBuilder 返回类型
     */
    private fun concatParams(params: Map<String, Any>?): StringBuilder {
        val builder = StringBuilder("") //请求参数为空给一个默认值空字符串
        //判断是空
        if (ObjectUtil.isNotEmpty(params)) {
            var i = 0
            for (key in params!!.keys) {
                val value = params[key]
                builder.append(if (i != 0) "&" else "")
                builder.append("$key=$value")
                i++
            }
        }
        return builder
    }

    /**
     * @Description 创建支持https请求
     * @Author        liangjl
     * @Date        2018年2月9日 下午3:25:47
     * @param url
     * @param reqMap
     * @param contentType 参数
     * @return void 返回类型
     * @throws
     */
    fun createHttpsPost(url: String?, reqMap: Map<String, Any>?, contentType: String): String {
        val buffer = StringBuilder("")

        /**忽略SSL协议证书 */
        val build = OkHttpClient.Builder().sslSocketFactory(createSSLSocketFactory())
            .hostnameVerifier(TrustAllHostnameVerifier()).build()
        val body = createRequestBody(contentType, reqMap)
        val request = Request.Builder().url(url).post(body).build()
        val call = build.newCall(request)
        call.enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {}

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                val res = response.body()!!.string()
                buffer.append(res)
                semaphoreInstance!!.release() //释放
            }
        })
        try {
            semaphoreInstance!!.acquire()
        } catch (e1: InterruptedException) {
            e1.printStackTrace()
        }
        return buffer.toString()
    }

    /**
     * @Description createSSLSocketFactory
     * @Author        liangjl
     * @Date        2018年2月9日 下午3:15:47
     * @return 参数
     * @return SSLSocketFactory 返回类型
     * @throws
     */
    private fun createSSLSocketFactory(): SSLSocketFactory? {
        var ssfFactory: SSLSocketFactory? = null
        try {
            val sc = SSLContext.getInstance("TLS")
            sc.init(null, arrayOf<TrustManager>(TrustAllCerts()), SecureRandom())
            ssfFactory = sc.socketFactory
        } catch (e: Exception) {
        }
        return ssfFactory
    }

    /**
     *
     * @Description 获取当前类名包含有包名路径
     * @Author      liangjilong
     * @Date        2017年5月24日 上午10:33:49
     * @param @return 参数
     * @return String 返回类型
     * @throws
     */
    val currentClassName: String
        get() = OkHttpClientUtil::class.java.name

    /**
     * @Description    TrustAllCerts
     * @ClassName    TrustAllCerts
     * @Date        2018年2月9日 下午3:15:23
     * @Author        liangjl
     * @Copyright (c) All Rights Reserved, 2018.
     */
    private class TrustAllCerts : X509TrustManager {
        @Throws(CertificateException::class)
        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        @Throws(CertificateException::class)
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
        }

        override fun getAcceptedIssuers(): Array<X509Certificate?> {
            return arrayOfNulls(0)
        }
    }

    /**
     * @Description    验证所有主机
     * @ClassName    TrustAllHostnameVerifier
     * @Date        2018年2月9日 下午3:15:34
     * @Author        liangjl
     * @Copyright (c) All Rights Reserved, 2018.
     */
    private class TrustAllHostnameVerifier : HostnameVerifier {
        override fun verify(hostname: String, session: SSLSession): Boolean {
            return true
        }
    }

    /**
     * @Description    定义一个回调成功的接口.
     * @ClassName    IOkHttpClientCallBack
     * @Date        2018年2月9日 下午3:34:18
     * @Author        liangjl
     * @Copyright (c) All Rights Reserved, 2018.
     */
    interface IOkHttpClientCallBack {
        fun onSuccessful(retBody: String?)
    }
}


/**
 *所有请求基类
 */
open class RequestBuilder<R> {
    /**
     * lazy 懒加载,用到的时候再加载
     */
    private val gson by lazy { Gson() }

    /**
     * 解析网络请求结果,自动转换成R的实体数据类型对象
     */
    fun parseResult(result: String?): R {
        //获取泛型类型
        val type = (this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
        return gson.fromJson(result, type)
    }

}
